package kz.pompei.ifacer.visio.def.paint;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JOptionPane;

import kz.pompei.ifacer.grot.CommonField;
import kz.pompei.ifacer.grot.FontDot;
import kz.pompei.ifacer.grot.acts.Act;
import kz.pompei.ifacer.grot.acts.ChangeFieldsAct;
import kz.pompei.ifacer.model.CursorInfo;
import kz.pompei.ifacer.model.CursorKind;
import kz.pompei.ifacer.model.PaintKind;
import kz.pompei.ifacer.model.widgets.Align;
import kz.pompei.ifacer.model.widgets.WidgetLabel;
import kz.pompei.ifacer.util.RichText;
import kz.pompei.ifacer.util.TextSize;
import kz.pompei.ifacer.visio.PaintUtil;
import kz.pompei.ifacer.visio.WidgetProp;

public class PaintWidgetLabel {
  
  private static final int MARKER_WIDTH = 5;
  
  private Rectangle getMarkerRect(Graphics2D g, WidgetLabel w) {
    TextSize size = RichText.parse(w.text).getSize(g.create());
    int height = size.height();
    
    switch (w.side) {
    case LEFT:
      return new Rectangle(w.x, w.y, MARKER_WIDTH, height + PaintUtil.BOTTOM_OFFSET);
      
    case RIGHT:
      return new Rectangle(w.x - MARKER_WIDTH, w.y, MARKER_WIDTH, height + PaintUtil.BOTTOM_OFFSET);
      
    default:
      throw new IllegalArgumentException("Unknown value: " + w.side);
    }
  }
  
  private Rectangle getTextRect(Graphics2D g, WidgetLabel w) {
    if (w.text == null || w.text.trim().length() == 0) return null;
    
    RichText rt = RichText.parse(w.text);
    TextSize size = rt.getSize(g.create());
    
    int width = size.width;
    int height = size.height();
    
    switch (w.side) {
    case LEFT:
      return new Rectangle(w.x + MARKER_WIDTH, w.y, width, height + PaintUtil.BOTTOM_OFFSET);
      
    case RIGHT:
      return new Rectangle(w.x - width - MARKER_WIDTH, w.y, width, height + PaintUtil.BOTTOM_OFFSET);
      
    default:
      throw new IllegalArgumentException("Unknown value: " + w.side);
    }
  }
  
  public void paint(Graphics2D g, WidgetLabel w, PaintKind paintKind, Point mouse,
      Rectangle allSpace) {
    Rectangle mr = getMarkerRect(g, w);
    Rectangle tr = getTextRect(g, w);
    if (paintKind != PaintKind.NORMAL || tr == null) {
      if (mr.contains(mouse)) {
        g.setColor(Color.GRAY);
        g.fillRect(mr.x, mr.y, mr.width, mr.height);
      }
      g.setColor(paintKind.isOver() ? Color.BLUE :Color.BLACK);
      g.drawRect(mr.x, mr.y, mr.width, mr.height);
    }
    
    g.setColor(paintKind.isOver() ? Color.BLUE :Color.BLACK);
    
    if (tr != null) {
      RichText rt = RichText.parse(w.text);
      TextSize size = rt.getSize(g.create());
      rt.draw(g.create(), tr.x, tr.y + size.ascent, true);
    }
    
    if (paintKind.isSel()) {
      Rectangle all = mr;
      if (tr != null) all = all.union(tr);
      PaintUtil.drawSelectionRect(g, all.x, all.y, all.width, all.height);
    }
  }
  
  public Rectangle getWidgetBound(Graphics2D g, WidgetLabel w) {
    Rectangle ret = getMarkerRect(g, w);
    Rectangle tr = getTextRect(g, w);
    if (tr != null) ret = ret.union(tr);
    return ret;
  }
  
  public CursorInfo getCursorInfo(Graphics2D g, WidgetLabel w, Point mouse) {
    Rectangle tr = getTextRect(g, w);
    Rectangle mr = getMarkerRect(g, w);
    if (tr == null) {
      if (!mr.contains(mouse)) return null;
      return new CursorInfo(CursorKind.MOVE, "edit");
    }
    
    if (mr.contains(mouse)) {
      return new CursorInfo(CursorKind.MOVE, "from" + w.side.name());
    }
    
    Rectangle all = tr.union(mr);
    if (all.contains(mouse)) {
      return new CursorInfo(CursorKind.MOVE, "edit");
    }
    
    return null;
  }
  
  public Act move(Graphics2D g, WidgetLabel original, WidgetLabel copy, Point fromPoint,
      Point toPoint) throws Exception {
    copy.takePosition(original);
    copy.move(toPoint.x - fromPoint.x, toPoint.y - fromPoint.y);
    return new ChangeFieldsAct(original.uuid, "x", copy.x, "y", copy.y);
  }
  
  public Act getDoubleClickAct(Graphics2D g, WidgetLabel w, Point mouse, JComponent owner)
      throws Exception {
    Rectangle mr = getMarkerRect(g, w);
    Rectangle tr = getTextRect(g, w);
    
    if (tr == null) {
      if (mr.contains(mouse)) return changeText(w, owner);
      return null;
    }
    
    Rectangle all = mr;
    if (tr != null) all = all.union(tr);
    
    if (mr.contains(mouse)) return changeSide(w, all);
    
    if (mr.union(tr).contains(mouse)) return changeText(w, owner);
    
    return null;
  }
  
  private Act changeSide(WidgetLabel w, Rectangle all) {
    int newX = all.x + all.width;
    Align newSide = Align.RIGHT;
    if (w.side == Align.RIGHT) {
      newX = all.x;
      newSide = Align.LEFT;
    }
    return new ChangeFieldsAct(w.uuid, "side", newSide, "x", newX);
  }
  
  private Act changeText(WidgetLabel w, JComponent owner) {
    String newText = JOptionPane.showInputDialog(owner, "Укажите новый текст", w.text);
    if (newText == null) return null;
    return new ChangeFieldsAct(w.uuid, "text", newText);
  }
  
  public Act setProperty(Graphics2D g, WidgetLabel w, WidgetProp prop, int value) throws Exception {
    ///////////////////////////////
    if (
    
    (prop == WidgetProp.LEFT && w.side == Align.LEFT)
    
    ||
    
    (prop == WidgetProp.RIGHT && w.side == Align.RIGHT)
    
    ) {
      return new ChangeFieldsAct(w.uuid, "x", value);
    }
    ///////////////////////////////
    if (prop == WidgetProp.LEFT && w.side == Align.RIGHT) {
      Rectangle b = getWidgetBound(g, w);
      return new ChangeFieldsAct(w.uuid, "x", value + b.width);
    }
    ///////////////////////////////
    if (prop == WidgetProp.RIGHT && w.side == Align.LEFT) {
      Rectangle b = getWidgetBound(g, w);
      return new ChangeFieldsAct(w.uuid, "x", value - b.width);
    }
    ///////////////////////////////
    
    if (prop == WidgetProp.TOP) {
      return new ChangeFieldsAct(w.uuid, "y", value);
    }
    if (prop == WidgetProp.BOTTOM) {
      Rectangle b = getWidgetBound(g, w);
      return new ChangeFieldsAct(w.uuid, "y", value - b.height);
    }
    
    return null;
  }
  
  public Set<CommonField> getChangableFields(Graphics2D g, WidgetLabel widget, Point mouse) {
    Set<CommonField> ret = new HashSet<>();
    ret.add(CommonField.COLOR);
    ret.add(CommonField.FONT);
    return ret;
  }
  
  public Object getFieldValue(Graphics2D g, CommonField cf, WidgetLabel w, Point mouse) {
    RichText rt = RichText.parse(w.text);
    switch (cf) {
    case FONT:
      return new FontDot(rt.getFirstFontFamily(), rt.getFirstFontSize());
      
    case COLOR:
      return rt.getFirstColor();
      
    default:
      throw new IllegalArgumentException("Cannot get " + cf + " from " + w.getClass());
    }
  }
  
  public Act setFieldValue(Graphics2D g, WidgetLabel w, CommonField cf, Object fieldValue,
      Point mouse) {
    if (fieldValue == null) return null;
    
    RichText rt = RichText.parse(w.text);
    switch (cf) {
    case FONT:
      FontDot fontDot = (FontDot)fieldValue;
      rt.setFontFamilyEverywhere(fontDot.family);
      rt.setFontSizeEverywhere(fontDot.size);
      break;
    
    case COLOR:
      Color color = (Color)fieldValue;
      rt.setColorEverywhere(color);
      break;
    
    default:
      throw new IllegalArgumentException("Cannot set " + cf + " from " + w.getClass());
    }
    
    String newText = rt.compile();
    
    if (newText.equals(w.text)) return null;
    
    return new ChangeFieldsAct(w.uuid, "text", newText);
  }
}
